<template>
  <div>
    <el-row type="flex" justify="center">
      <el-input v-model="numberString" size="mini"></el-input>
      <el-button type="primary" size="mini" @click="onSubmit">开始排序</el-button>
    </el-row>
    <div id="myBucketChart" :style="{width: '600px', height: '300px'}"></div>
    <div id="myResultChart" :style="{width: '600px', height: '300px'}"></div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      numberString: '2,1,3,6,9,8,7',
      numbers: [],
      max: undefined,
      min: undefined,
      step: undefined,
      bucketCount: 0,
      bucketList: [
        {
          start: undefined,
          end: undefined,
          list: undefined
        }
      ],
      bucketOption: {
        grid: {
          left: '3%',
          right: '4%',
          bottom: '3%',
          containLabel: true
        },
        xAxis: {
          type: 'category',
          data: [],
          animationDuration: 0,
          animationDurationUpdate: 400,
        },
        yAxis: {
          type: 'value'
        },
        series: [
          {
            type: 'bar',
            stack: 'total',
            data: []
          }
        ],
        animationDuration: 0,
        animationDurationUpdate: 400
      },
      resultOption: {
        xAxis: {
          type: 'category',
          data: [],
          animationDuration: 0,
          animationDurationUpdate: 400,
        },
        yAxis: {
          type: 'value'
        },
        series: [{
          data: [{
            value: undefined,
            itemStyle: {
              color: '#6e7074'
            }
          }],
          type: 'bar',
          label: {
            show: true,
          }
        }],
        animationDuration: 0,
        animationDurationUpdate: 400
      },
      stateObjectArray: [
        {
          bucketListState: [
            {
              star: undefined,
              end: undefined,
              list: []
            }
          ],
          sortListState: {
            start: undefined,
            end: undefined,
            keyIndex: undefined,
            data: []
          }
        }
      ]
    }
  },
  components: {},
  computed: {},
  watch: {},
  mounted() {
    this.initialEcharts()
  },
  created() {
  },
  methods: {
    onSubmit() {
      this.resetAllData()
      this.dealWithInput()
    },
    resetAllData() {
      this.numbers = []
      this.bucketCount = 0
      this.bucketOption.series = []
      this.bucketOption.xAxis.data = []
      this.bucketList = []

      this.resultOption.series[0].data = []
      this.resultOption.xAxis.data = []

      this.stateObjectArray = []
    },
    dealWithInput() {
      this.getNumbers()
      this.getBucketXData()
      this.putNumbersIntoBucket()
      this.sortBuckets()
      this.initialResultData()
      this.getNumberFromBucket()
      this.draw()
    },
    transBucketIntoSeriesData(bucket, bucketIndex) {
      if (!bucket.list || bucket.list.length === 0) {
        return []
      }

      let result = []
      for (let j = 0; j < bucket.list.length; j++) {
        let number = bucket.list[j]
        let data = []
        for (let k = 0; k < this.bucketCount; k++) {
          data[k] = k === bucketIndex ? number : 0
        }
        let newData = {
          type: 'bar',
          stack: 'total',
          data: data,
          label: {
            show: true,
            formatter: function (data) {
              return data.data > 0 ? data.data : ''
            }
          },
        }
        result.push(newData)
      }
      return result
    },
    drawCurrentState(state) {
      this.bucketOption.series = []
      this.myResultChart.setOption(this.bucketOption, true)
      // this.myResultChart.clear()

      let bucketState = state.bucketListState
      let data = []
      for (let index = 0; index < bucketState.length; index++) {
        let bucket = bucketState[index]
        data.push(...this.transBucketIntoSeriesData(bucket, index))
      }

      this.bucketOption.series = data
      this.myBucketChart.setOption(this.bucketOption, true)

      let sortState = state.sortListState

      if (sortState) {
        // console.log('sortState.list', sortState.keyIndex, sortState.data)
        this.resultOption.xAxis.data = []
        let list = sortState.data.map(x => {
          // if (x === sortState.keyIndex) {
          //   return {
          //     value: x,
          //     itemStyle: {
          //       color: '#FF7C7C'
          //     }
          //   }
          // } else {
          return {
            value: x,
            itemStyle: {
              color: '#6e7074'
            }
          }
          // }
        })
        // console.log('list', list)
        if (list && list[sortState.keyIndex]) {
          list[sortState.keyIndex].itemStyle.color = '#FF7C7C'
        }
        for (let ii = 0; ii < list.length; ii++) {
          this.resultOption.xAxis.data.push(ii)
        }
        this.resultOption.series[0].data = list
        this.myResultChart.setOption(this.resultOption, true)
      }

    },
    draw() {
      let i = 0
      let outLoop = () => {
        if (i >= this.stateObjectArray.length) {
          return
        }

        setTimeout(() => {
          this.drawCurrentState(JSON.parse(JSON.stringify(this.stateObjectArray[i])));
          i++;
          outLoop();
        }, 400)

      }

      outLoop()
    },
    getNumberFromBucket() {
      for (let i = 0; i < this.bucketList.length; i++) {
        let bucket = this.bucketList[i]

        if (bucket.list && bucket.list.length > 0) {
          let deleteList = []
          for (let j = 0; j < bucket.list.length; j++) {
            let number = bucket.list[j]
            deleteList.push(number)
            let newBucket = JSON.parse(JSON.stringify(bucket))
            newBucket.list = this.filter(newBucket.list, deleteList)
            this.addNumberToState(newBucket, number)
          }
        }
      }
    },
    filter(array0, array1) {
      return array0.filter(function (v) {
        return array1.indexOf(v) === -1
      })
    },
    initialResultData() {
      this.pushStateBySortBucket(0, 0, 0, [])
    },
    sortBuckets() {
      for (let i = 0; i < this.bucketList.length; i++) {
        let bucket = this.bucketList[i]
        let list = bucket.list
        if (list && list.length > 1) {
          this.sortArray(list)
          this.pushStateByUpdateBucket(bucket)
        }
      }
    },
    sortArray(array) {
      this.sort(0, array.length - 1, array)
    },
    sort(start, end, array) {
      if (start > end) {
        return
      }
      let startBack = start
      let endBack = end
      let key = array[start]
      let keyIndex = start
      this.pushStateBySortBucket(start, end, keyIndex, array)
      while (start < end) {
        while (array[end] >= key && end > start) {
          end--;
          this.pushStateBySortBucket(start, end, keyIndex, array)
        }
        if (start < end) {
          this.swap(keyIndex, end, array)
          keyIndex = end
          this.pushStateBySortBucket(start, end, keyIndex, array)
        }
        while (array[start] < key && start < end) {
          start++;
          this.pushStateBySortBucket(start, end, keyIndex, array)
        }
        if (start < end) {
          this.swap(start, keyIndex, array)
          keyIndex = start
          this.pushStateBySortBucket(start, end, keyIndex, array)
        }
      }
      this.sort(startBack, end - 1, array)
      this.sort(start + 1, endBack, array)
    },
    swap(index1, index2, array) {
      let t = array[index1]
      array[index1] = array[index2];
      array[index2] = t;
    },
    putNumbersIntoBucket() {
      for (let i = 0; i < this.numbers.length; i++) {
        let number = this.numbers[i]
        let bucketIndex = Math.floor((number - this.min) / this.step)
        let bucket = JSON.parse(JSON.stringify(this.bucketList[bucketIndex]))
        bucket.list.push(number)
        this.bucketList[bucketIndex].list.push(number)
        this.pushStateByUpdateBucket(bucket)
      }
    },
    getBucketXData() {
      this.max = this.numbers[0]
      this.min = this.numbers[0]
      for (let i = 0; i < this.numbers.length; i++) {
        this.max = Math.max(this.max, this.numbers[i])
        this.min = Math.min(this.min, this.numbers[i])
      }
      let deltaValue = this.max - this.min
      let count = this.numbers.length
      this.step = Math.floor(deltaValue / count) + 1
      this.bucketCount = Math.floor(deltaValue / this.step) + 1
      for (let i = 0; i < this.bucketCount; i++) {
        let start = this.min + i * this.step
        let end = this.min + (i + 1) * this.step
        let s = start + '~' + end
        this.getBucketList(start, end)
        this.bucketOption.xAxis.data.push(s)
      }
    },
    getBucketList(start, end) {
      let o = {}
      o.start = start
      o.end = end
      o.list = []
      this.bucketList.push(o)
      if (this.stateObjectArray.length === 0) {
        this.setFirstState(o)
      } else {
        this.pushStateByCreateBucket(o)
      }
    },
    setFirstState(bucket) {
      let back = JSON.parse(JSON.stringify(bucket))
      this.stateObjectArray[0] = {
        bucketListState: [back]
      }
    },
    pushStateByCreateBucket(bucket) {
      let back = JSON.parse(JSON.stringify(bucket))
      let lastState = this.stateObjectArray[this.stateObjectArray.length - 1]
      let newState = JSON.parse(JSON.stringify(lastState))
      newState.bucketListState.push(back)
      this.stateObjectArray.push(newState)
    },
    pushStateByUpdateBucket(bucket) {
      let back = JSON.parse(JSON.stringify(bucket))
      let bucketIndex = (bucket.start - this.min) / this.step
      let lastState = JSON.parse(JSON.stringify(this.stateObjectArray[this.stateObjectArray.length - 1]))
      lastState.bucketListState[bucketIndex] = back
      this.stateObjectArray.push(lastState)
    },
    pushStateBySortBucket(start, end, keyIndex, array) {
      let lastState = JSON.parse(JSON.stringify(this.stateObjectArray[this.stateObjectArray.length - 1]))
      lastState.sortListState = {
        start: start,
        end: end,
        keyIndex: keyIndex,
        data: array
      }
      this.stateObjectArray.push(lastState)
    },
    addNumberToState(newBucket, number) {
      let lastState = JSON.parse(JSON.stringify(this.stateObjectArray[this.stateObjectArray.length - 1]))
      if (!lastState.sortListState.data) {
        lastState.data = []
      }
      lastState.sortListState.data.push(number)

      let bucketIndex = (newBucket.start - this.min) / this.step
      lastState.bucketListState[bucketIndex] = newBucket
      this.stateObjectArray.push(lastState)
    },
    // 把输入转为数字
    getNumbers() {
      this.numbers = this.numberString.split(',').map(x => parseInt(x)).filter(m => this.isRealNum(m))
    },
    // 判断输入是否为数字
    isRealNum(value) {
      if (value === '' || value === null) {
        return false
      }
      return !isNaN(value) && typeof value === 'number'
    },
    // 初始化两个图
    initialEcharts() {
      var myBucketChartDom = document.getElementById('myBucketChart');
      this.myBucketChart = this.$echarts.init(myBucketChartDom)

      var myResultChartDom = document.getElementById('myResultChart');
      this.myResultChart = this.$echarts.init(myResultChartDom)
    }
  }
}
</script>
<style></style>
